﻿using System;
using Lazy.Captcha.Core.Generator.Code;
using Lazy.Captcha.Core.Generator.Image;
using Lazy.Captcha.Core.Storage;
using Lazy.Captcha.Core.RateLimit;

namespace Lazy.Captcha.Core
{
    public class CaptchaService
    {
        private readonly CaptchaOptions CaptchaOptions;
        private readonly IStorage Storage;
        private readonly IRateLimiter RateLimiter;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="captchaOptions"></param>
        /// <param name="storage"></param>
        /// <param name="rateLimiter"></param>
        public CaptchaService(CaptchaOptions captchaOptions, IStorage storage, IRateLimiter rateLimiter = null)
        {
            CaptchaOptions = captchaOptions;
            Storage = storage;
            RateLimiter = rateLimiter ?? new MemoryRateLimiter();
        }

        /// <summary>
        /// 生成验证码
        /// </summary>
        /// <param name="captchaId">验证码id</param>
        /// <param name="expirySeconds">缓存时间，未设定则使用配置时间</param>
        /// <returns></returns>
        public virtual CaptchaData Generate(string captchaId, int? expirySeconds = null)
        {
            var _captchaCodeGenerator = GetCodeGenerator();
            var _captchaImageGenerator = GetImageGenerator();

            var (renderText, code) = _captchaCodeGenerator.Generate(CaptchaOptions.CodeLength);
            var image = _captchaImageGenerator.Generate(renderText, CaptchaOptions.ImageOption);
            expirySeconds = expirySeconds.HasValue ? expirySeconds.Value : CaptchaOptions.ExpirySeconds;
            Storage.Set(captchaId, code, DateTime.Now.AddSeconds(expirySeconds.Value).ToUniversalTime());

            return new CaptchaData(captchaId, code, image);
        }

        /// <summary>
        /// 生成验证码（带频率限制）
        /// </summary>
        /// <param name="captchaId">验证码id</param>
        /// <param name="rateLimitKey">频率限制键（如IP地址、用户ID等）</param>
        /// <param name="expirySeconds">缓存时间，未设定则使用配置时间</param>
        /// <returns></returns>
        public virtual CaptchaData GenerateWithRateLimit(string captchaId, string rateLimitKey, int? expirySeconds = null)
        {
            // 检查频率限制
            var rateLimitResult = CheckRateLimit(rateLimitKey);
            if (!rateLimitResult.IsAllowed)
            {
                throw new RateLimitExceededException(
                    rateLimitResult.RemainingRequests,
                    rateLimitResult.ResetTime,
                    rateLimitResult.WindowSeconds,
                    rateLimitResult.MaxRequests);
            }

            return Generate(captchaId, expirySeconds);
        }

        /// <summary>
        /// 检查频率限制
        /// </summary>
        /// <param name="rateLimitKey">频率限制键</param>
        /// <returns></returns>
        public virtual RateLimitResult CheckRateLimit(string rateLimitKey)
        {
            if (!CaptchaOptions.RateLimit.Enabled)
            {
                return RateLimitResult.Allowed(rateLimitKey, CaptchaOptions.RateLimit.MaxRequests, null,
                    CaptchaOptions.RateLimit.WindowSeconds, CaptchaOptions.RateLimit.MaxRequests);
            }

            var isAllowed = RateLimiter.IsAllowed(rateLimitKey,
                CaptchaOptions.RateLimit.WindowSeconds,
                CaptchaOptions.RateLimit.MaxRequests);

            var remainingRequests = RateLimiter.GetRemainingRequests(rateLimitKey,
                CaptchaOptions.RateLimit.WindowSeconds,
                CaptchaOptions.RateLimit.MaxRequests);

            var resetTime = RateLimiter.GetResetTime(rateLimitKey, CaptchaOptions.RateLimit.WindowSeconds);

            if (isAllowed)
            {
                return RateLimitResult.Allowed(rateLimitKey, remainingRequests, resetTime,
                    CaptchaOptions.RateLimit.WindowSeconds, CaptchaOptions.RateLimit.MaxRequests);
            }
            else
            {
                return RateLimitResult.Denied(rateLimitKey, remainingRequests, resetTime,
                    CaptchaOptions.RateLimit.WindowSeconds, CaptchaOptions.RateLimit.MaxRequests);
            }
        }

        protected virtual ICaptchaImageGenerator GetImageGenerator()
        {
            return new DefaultCaptchaImageGenerator();
        }

        protected virtual ICaptchaCodeGenerator GetCodeGenerator()
        {
            return new DefaultCaptchaCodeGenerator(CaptchaOptions.CaptchaType);
        }

        /// <summary>
        /// 校验
        /// </summary>
        /// <param name="captchaId">验证码id</param>
        /// <param name="code">用户输入的验证码</param>
        /// <param name="removeIfSuccess">校验成功时是否移除缓存(用于多次验证)</param>
        /// <param name="removeIfFail">校验失败时是否移除缓存</param>
        /// <returns></returns>
        public virtual bool Validate(string captchaId, string code, bool removeIfSuccess = true, bool removeIfFail = true)
        {
            var val = Storage.Get(captchaId);
            var comparisonType = CaptchaOptions.IgnoreCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture;
            var success = !string.IsNullOrWhiteSpace(code) &&
                          !string.IsNullOrWhiteSpace(val) &&
                          string.Equals(val, code, comparisonType);

            if ((!success && removeIfFail) || (success && removeIfSuccess))
            {
                Storage.Remove(captchaId);
            }

            return success;
        }
    }
}
